// C library headers
#include <assert.h>
#include <atomic>
#include <cstdint>
#include <iostream>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <vector>

#include "check_sum.h"
#include "serial.h"

#if 0
int main() {
  int serial_port = open("/dev/ttyS1", O_RDWR | O_NOCTTY);
  set_opt(serial_port, 115200, 8, 'N', 1);

  char rx_buff[256]{0};

  while (1) {
    memset(rx_buff, 0, sizeof(rx_buff));
    int num_bytes = read(serial_port, rx_buff, sizeof(rx_buff));
    std::cout << "receive num: " << num_bytes << ". data: " << rx_buff << std::endl;
  }

  close(serial_port);
  return 0; // success
}
#else

static std::atomic_bool run_flag{true};
static void signal_handler(int sig) {
  if (sig == SIGINT) {
    run_flag.store(false);
  }
}

static int32_t rx_tool(int fd, void *buff, int32_t len) {
  uint8_t *rx_buff = static_cast<uint8_t *>(buff);
  int32_t rx_acc = 0;
  while (rx_acc < len && run_flag.load()) {
    auto rx_num = read(fd, rx_buff + rx_acc, len - rx_acc);
    rx_acc += (rx_num > 0) ? rx_num : 0;
  }

  return rx_acc;
}

int main() {
  signal(SIGINT, signal_handler);
  uint32_t max_pl_len = 0;
  int32_t frame_count = 0;

  int serial_port = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NONBLOCK);
  set_opt(serial_port, 115200, 8, 'N', 1);

  while (run_flag.load()) {
    uint32_t pl_len = 0;
    auto rx_len = rx_tool(serial_port, &pl_len, sizeof(pl_len));
    if (!run_flag.load())
      break;

    assert(pl_len > 0 && pl_len < (8 * 1024));
    std::vector<uint8_t> rx_payload(pl_len);
    uint8_t *rx_data = rx_payload.data();
    rx_tool(serial_port, rx_data, pl_len);

    uint32_t rd_cs = *((uint32_t *)(rx_data + pl_len - 4));
    uint32_t calc_cs = make_checksum_32(rx_data, pl_len - 4);
    if (calc_cs != rd_cs) {
      std::cout << std::hex << "checksum not match: " << rd_cs << " vs " << calc_cs << std::dec << std::endl;
      break;
    }

    frame_count++;
    std::cout << "received a frame, frame count: " << frame_count << std::endl;
    if (pl_len > max_pl_len) {
      max_pl_len = pl_len;
    }
  }

  std::cout << "frame count: " << frame_count << std::endl;
  return 0;
}
#endif